using UnityEngine;

namespace NL.Advanced
{
    public static class FrustumTools
    {
        /// <summary>
        /// 根据相机和世界坐标判断坐标点是否在相机视锥内
        /// </summary>
        /// <param name="cam"></param>
        /// <param name="worldPosition"></param>
        /// <returns></returns>
        public static bool CheckInFrustumWithPosition(this Camera cam, Vector3 worldPosition, float border = 0)
        {
            var screenRect = new Rect(border * Screen.width, border * Screen.height, Screen.width * (1 - border * 2), Screen.height * (1 - border * 2));
            var screenPos = cam.WorldToScreenPoint(worldPosition);
            return screenRect.Contains(screenPos);
        }

        public static bool CheckInFrustumWithMeshBounds(this Camera cam, MeshRenderer[] meshRenderers)
        {
            var frustumPlanes = GeometryUtility.CalculateFrustumPlanes(cam);
            Bounds meshBounds = new Bounds();
            foreach (var render in meshRenderers)
            {
                meshBounds.Encapsulate(render.bounds);
            }

            return GeometryUtility.TestPlanesAABB(frustumPlanes, meshBounds);
        }

        public static bool CheckInFrustumWithColliderBounds(this Camera cam, BoxCollider[] colliders)
        {
            Bounds colliderBound = new Bounds();
            foreach (var col in colliders)
            {
                colliderBound.Encapsulate(col.bounds);
            }

            var viewportBounds = cam.GetViewportBounds();
            return colliderBound.Intersects(viewportBounds);
        }

        private static Bounds GetViewportBounds(this Camera cam)
        {
            var lowerLeft = cam.ViewportToWorldPoint(new Vector3(0, 0, cam.nearClipPlane));
            var upperRight = cam.ViewportToWorldPoint(new Vector3(1, 1, cam.nearClipPlane));
            return new Bounds((lowerLeft + upperRight) / 2, upperRight - lowerLeft);
        }
    }
}